<?php
require_once IWeb::$app->getBasePath() . 'vendor/autoload.php';

use Predis\Client;
use Predis\Response\Status;
use Predis\Connection\ConnectionException;

class IRedis
{
    private $client;
    private static $instance;

    // 私有构造方法防止直接实例化
    private function __construct($database = null)
    {
        try {
            $config = new Config('redis_config');
            $redisConfig = $config->getInfo();

            // 获取允许的数据库范围
            $minDb = isset($redisConfig['min_db']) ? $redisConfig['min_db'] : 20;
            $maxDb = isset($redisConfig['max_db']) ? $redisConfig['max_db'] : 25;

            // 验证数据库编号是否在允许范围内
            if ($database !== null) {
                if ($database < $minDb || $database > $maxDb) {
                    throw new Exception("数据库编号必须在{$minDb}到{$maxDb}之间");
                }
                $redisConfig['database'] = $database;
            }
            $this->client = new Client([
                'scheme' => $redisConfig['scheme'] ?? 'tcp',
                'host'   => $redisConfig['host'] ?? '127.0.0.1',
                'port'   => $redisConfig['port'] ?? 6379,
                'password' => $redisConfig['password'] ?? null,
                'database' => $redisConfig['database'] ?? $minDb,
            ]);

            // 测试连接
            $this->client->ping();
        } catch (\Exception $e) {  // 捕获所有异常类型确保连接失败被检测到
            throw new Exception("Redis连接失败: " . $e->getMessage());
        }
    }

    // 获取单例实例
    public static function getInstance($database = null)
    {
        if (!self::$instance instanceof self) {
            self::$instance = new self($database);
        }
        return self::$instance;
    }

    // 封装zRemRangeByScore方法（移除指定分数范围的成员）
    public function zRemRangeByScore($key, $minScore, $maxScore)
    {
        return $this->client->zremrangebyscore($key, $minScore, $maxScore);
    }

    // 封装zAdd方法（添加有序集合成员）
    public function zAdd($key, $score, $member)
    {
        return $this->client->zadd($key, $score, $member);
    }

    // 封装zCard方法（获取有序集合成员数量）
    public function zCard($key)
    {
        return $this->client->zcard($key);
    }

    // 新增：封装 Redis multi 方法（开始事务）
    public function multi()
    {
        return $this->client->multi();
    }

    // 新增：封装Redis的hIncrBy方法
    public function hIncrBy($key, $field, $increment = 1)
    {
        return $this->client->hincrby($key, $field, $increment);
    }

    // 设置键值
    public function set($key, $value, $expire = null)
    {
        if ($expire) {
            return $this->client->setex($key, $expire, $value);
        }
        return $this->client->set($key, $value);
    }

    // 获取键值
    public function get($key)
    {
        return $this->client->get($key);
    }

    // 删除键
    public function del($key)
    {
        return $this->client->del($key);
    }

    // 检查键是否存在
    public function exists($key)
    {
        return $this->client->exists($key);
    }

    // 新增：封装 Redis setex 方法（设置键值并指定过期时间）
    public function setex($key, $seconds, $value)
    {
        return $this->client->setex($key, $seconds, $value);
    }

    // 新增：封装 Redis exec 方法（执行事务）
    public function exec()
    {
        return $this->client->exec();
    }

    // 哈希表操作
    public function hset($hash, $field, $value)
    {
        return $this->client->hset($hash, $field, $value);
    }

    // 获取哈希字段值
    public function hget($hash, $field)
    {
        return $this->client->hget($hash, $field);
    }

    // 获取所有哈希字段
    public function hgetall($hash)
    {
        return $this->client->hgetall($hash);
    }

    // 设置过期时间
    public function expire($key, $seconds)
    {
        return $this->client->expire($key, $seconds);
    }

    // 获取剩余生存时间
    public function ttl($key)
    {
        return $this->client->ttl($key);
    }

    // 关闭连接
    public function close()
    {
        $this->client->disconnect();
    }
}
